home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Mac OS USB DDK / Examples / USBSampleStorageDriver / SampleStorageDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-16  |  39.1 KB  |  1,169 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SampleStorageDriver.c
  3.  
  4.     Contains:    All functions for the Class driverto access and control the device
  5.  
  6.     Version:        1.1
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Craig Keithley
  13.  
  14.         Other Contact:        xxx put other contact here xxx
  15.  
  16.         Technology:            USB Drivers
  17.  
  18.     Writers:
  19.  
  20.         (TM)    Tim McLeod
  21.         (CJK)    Craig Keithley
  22.  
  23.     Change History (most recent first):
  24.  
  25.       <USB3>     2/16/99    TM            Added an error code for class not configured. Changed all places
  26.                                     where the class driver was returning kNotConfigured to
  27.                                     kClassNotConfiguredErr. kNotConfigured is enumed to zero which
  28.                                     when returned as an error code makes the caller think that it is
  29.                                     getting a noErr.
  30.       <USB2>     1/11/99    CJK        update to use sources from 1.1f3 DDK
  31.  
  32. */
  33.  
  34.  
  35. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  36.     includes
  37.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  38. #include <Devices.h>
  39. #include <DriverServices.h>
  40. #include <Interrupts.h>
  41. #include <LowMem.h>
  42. #include <Folders.h>
  43. #include <MacTypes.h>
  44. #include <CodeFragments.h>
  45.  
  46. #include <USB.h>
  47.  
  48. #include "SampleStorageDriverAPI.h"
  49. #include "SampleStorageDeviceID.h"
  50. #include "SampleStorageDriver.h"
  51.  
  52. extern TheStorageClassDispatchTable;
  53.  
  54. enum
  55. {
  56.     kCString = 0,                // StateStr, USBStatusStr selector
  57.     kPString                        // StateStr, USBStatusStr selector
  58. };
  59.  
  60. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  61.     globals
  62.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  63. static             Boolean                            gBeenThereDoneThat = false;    // Flag indicating if this driver has been called before
  64.  
  65. static            Boolean                            gConfigured = false;                // No calls to dispatch table until this is true.
  66.  
  67. static            UInt32                            gConfigureStatus;                    // Current state of cinfiguration
  68.  
  69. static            Boolean                            gOKToRemoval = true;            // Used in StorageClassDriverNotifyProc to prevent removal by expert
  70.  
  71. static struct    StorageClassInfo                gStorageClassInfo;                // Holds all of the common items
  72.     
  73. static struct    StorageClassTransactionPB    gInterruptPB;                        // Used only for the interrupt pipe
  74.  
  75. static struct    StorageClassStatusPB            gGetStatusPB;                        // Used only for the USB Get Status request
  76.  
  77. static struct    StorageClassControlPB        gControlPB;                            // Used only for aborting a R/W transaction
  78.  
  79. static struct    StorageClassTransactionPB    gCommandPB;                            // Used only by StorageClassDriverExecuteCommand
  80.  
  81. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  82.     prototypes
  83.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  84.  
  85. static void InitParamBlock(USBDeviceRef theDeviceRef, USBPB* paramblock);
  86.  
  87. static Boolean    ImmediateError(OSStatus err);
  88.  
  89. static void    StorageDeviceConfigureCompletion(USBPB* pb);
  90.  
  91. static void    StorageDeviceInitiateConfiguration(USBPB* pb);
  92.  
  93. static OSStatus StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr );
  94.  
  95. static OSStatus StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr );
  96.  
  97. // Completion routines
  98.  
  99. static void ReadBlockCompletion(USBPB* usbPB);
  100.  
  101. static void WriteBlockCompletion(USBPB* usbPB);
  102.  
  103. static void ExecuteCommandCompletion(USBPB* usbPB);
  104.  
  105. static void ExecuteBufferedCommandCompletion(USBPB* usbPB);
  106.  
  107. static void GetStatusCompletion(USBPB* usbPB);
  108.  
  109. static void AbortTransactionCompletion(USBPB* usbPB);
  110.  
  111. //****************************************************************************************************
  112.  
  113. #if DEBUG
  114.  
  115. static void
  116. HexStr(    unsigned long    v,
  117.             unsigned char    *p )
  118. {
  119.     int    shift;
  120.     
  121.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  122.     {
  123.         char c = (v >> shift) & 0x0F;
  124.         *p++ = c + (c > 9? ('A'-10): '0');
  125.     }
  126. }
  127.  
  128. static unsigned char *
  129. USBStatusStr(    OSStatus    usbStatus,
  130.                     int        kind )
  131. {
  132.     unsigned char *p;
  133.  
  134.     switch ( usbStatus )
  135.     {
  136.         case    kUSBInternalErr:                    p = "\p" kStrStorageClass "Internal error"; break;
  137.         case    kUSBUnknownDeviceErr:            p = "\p" kStrStorageClass "Unknown device"; break;
  138.         case    kUSBUnknownPipeErr:                 p = "\p" kStrStorageClass "Unknown pipe"; break;
  139.         case    kUSBTooManyPipesErr:                p = "\p" kStrStorageClass "Too many pipes"; break;
  140.         case    kUSBIncorrectTypeErr:            p = "\p" kStrStorageClass "Incorrect type"; break;
  141.         case    kUSBRqErr:                            p = "\p" kStrStorageClass "Request error"; break;
  142.         case    kUSBUnknownRequestErr:            p = "\p" kStrStorageClass "Unknown request"; break;
  143.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrStorageClass "Too many transactions"; break;
  144.         case    kUSBAlreadyOpenErr:                p = "\p" kStrStorageClass "Already open"; break;
  145.         case    kUSBNoDeviceErr:                    p = "\p" kStrStorageClass "No device"; break;
  146.         case    kUSBDeviceErr:                        p = "\p" kStrStorageClass "Device error"; break;
  147.         case    kUSBOutOfMemoryErr:                p = "\p" kStrStorageClass "Out of memory"; break;
  148.         case    kUSBNotFound:                        p = "\p" kStrStorageClass "USB Not found"; break;
  149.         case    kUSBLinkErr:                        p = "\p" kStrStorageClass "Link Err"; break;
  150.         case    kUSBCRCErr:                            p = "\p" kStrStorageClass "Comms/Device err, bad CRC";  break;        
  151.         case    kUSBBitstufErr:                    p = "\p" kStrStorageClass "Comms/Device err, bitstuffing"; break;        
  152.         case    kUSBDataToggleErr:                p = "\p" kStrStorageClass "Comms/Device err, Bad data toggle"; break;        
  153.         case    kUSBEndpointStallErr:            p = "\p" kStrStorageClass "Device didn't understand"; break;        
  154.         case    kUSBNotRespondingErr:            p = "\p" kStrStorageClass "No device, device hung"; break;        
  155.         case    kUSBPIDCheckErr:                    p = "\p" kStrStorageClass "Comms/Device err, PID CRC error"; break;        
  156.         case    kUSBWrongPIDErr:                    p = "\p" kStrStorageClass "Comms/Device err, Bad or wrong PID"; break;        
  157.         case    kUSBOverRunErr:                    p = "\p" kStrStorageClass "Packet too large or more data than buffer"; break;        
  158.         case    kUSBUnderRunErr:                    p = "\p" kStrStorageClass "Less data than buffer"; break;        
  159.         case    kUSBRes1Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  160.         case    kUSBRes2Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  161.         case    kUSBBufOvrRunErr:                    p = "\p" kStrStorageClass "Buffer over run error"; break;        
  162.         case    kUSBBufUnderRunErr:                p = "\p" kStrStorageClass "Buffer under run error"; break;        
  163.         case    kUSBNotSent1Err:                    p = "\p" kStrStorageClass "Transaction not sent1"; break;        
  164.         case    kUSBNotSent2Err:                    p = "\p" kStrStorageClass "Transaction not sent2"; break;    
  165.         default:
  166.             p = "\p" kStrStorageClass "Unknown error nnnnnnnn";
  167.             HexStr( usbStatus, p + *p - 8 + 1 );
  168.             break;
  169.     }
  170.     
  171.     return kind == kPString? p: p + 1;
  172. }
  173.  
  174.  
  175. static unsigned char*
  176. StateStr(    OSStatus    refCon,
  177.                 int        kind )
  178. {
  179.     unsigned char *p;
  180.  
  181.     refCon &= ~(kCompletionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  182.     switch ( refCon )
  183.     {        
  184.         case kSetConfig:                                    p = kStrStorageClass "kSetConfig"; break;
  185.         case kGetFullConfiguration:                    p = kStrStorageClass "kGetFullConfiguration"; break;
  186.         case kFindStorageInterface:                    p = kStrStorageClass "kFindStorageInterface"; break;
  187.         case kStorageConfigureInterface:                p = kStrStorageClass "kStorageConfigureInterface"; break;
  188.         
  189.         case kNewInterfaceRef:                            p = kStrStorageClass "kNewInterfaceRef"; break;
  190.         case kStorageFindInterruptPipe:                p = kStrStorageClass "kStorageFindInterruptPipe"; break;
  191.         case kStorageFindBulkInPipe:                    p = kStrStorageClass "kStorageFindBulkInPipe"; break;
  192.         case kStorageFindBulkOutPipe:                    p = kStrStorageClass "kStorageFindBulkOutPipe"; break;
  193.                 
  194.         case kStorageReadInterrupt:                    p = kStrStorageClass "kStorageReadInterrupt"; break;
  195.         
  196.         case kStorageExecuteCommand:                    p = kStrStorageClass "kStorageExecuteCommand"; break;
  197.         case kStorageExecuteCommandCompletion:        p = kStrStorageClass "kStorageExecuteCommandCompletion"; break;
  198.         case kStorageBulkIOComplete:                    p = kStrStorageClass "kStorageBulkIOComplete"; break;
  199.         case kStorageGetStatus:                            p = kStrStorageClass "kStorageGetStatus"; break;
  200.         case kStorageGetStatusBulkRead:                p = kStrStorageClass "kStorageGetStatusBulkRead"; break;
  201.         
  202.         default:
  203.             p = "\pUnknown state nnnnnnnn";
  204.             HexStr( refCon, p + *p - 8 + 1 );
  205.             break;
  206.     }
  207.     return kind == kPString? p: p + 1;    
  208. }
  209. #endif
  210.  
  211. static unsigned char
  212. HiHex( int v )
  213. {
  214.     unsigned char    hinibble = (v >> 4) & 0x0f;
  215.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  216. }
  217.  
  218.  
  219. static unsigned char
  220. LoHex( int v )
  221. {
  222.     unsigned char    lonibble = v & 0x0f;
  223.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  224. }
  225.  
  226.  
  227. static void
  228. InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  229. {
  230.     paramblock->usbReference =    theDeviceRef;
  231.     paramblock->pbVersion =        kUSBCurrentPBVersion;
  232.     paramblock->pbLength =        sizeof(USBPB);
  233.     paramblock->usb.cntl.WIndex =        0;             
  234.     paramblock->usbBuffer =        nil;        
  235.     paramblock->usbStatus =        noErr;
  236.     paramblock->usbReqCount =    0;
  237.     paramblock->usb.cntl.WValue =        0;
  238.     paramblock->usbFlags =        0;
  239. }
  240.  
  241.  
  242. static Boolean
  243. ImmediateError(OSStatus err)
  244. {
  245.     return((err != kUSBPending) && (err != noErr) );
  246. }
  247.  
  248.  
  249. OSStatus
  250. GetUSBVersion(UInt32* usbVersion)
  251. {
  252. OSStatus result;
  253.  
  254.     result = Gestalt('usbv', usbVersion);
  255.     
  256.     return result;
  257. }
  258.  
  259.  
  260. OSErr
  261. GetInterfaceDescriptor(    LogicalAddress pConfigDesc,
  262.                                 UInt32 ReqInterface,
  263.                                 USBInterfaceDescriptorPtr * hInterfaceDesc)
  264. {
  265. UInt32                            totalLength;
  266. void *                            pEndOfDescriptors;
  267. USBInterfaceDescriptorPtr    pMyIntDesc;
  268. USBDescriptorHeaderPtr        pCurrentDesc;
  269. UInt32                            anAddress,
  270.                                     anOffset;
  271.  
  272.     totalLength =            ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength;
  273.     pEndOfDescriptors =    (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  274.     pCurrentDesc =            (USBDescriptorHeaderPtr)pConfigDesc;        // point the currentdesc to the start of the config space
  275.     
  276.     while (pCurrentDesc < pEndOfDescriptors)                                // as long as we haven't exhausted all the descriptors
  277.     {
  278.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)        // look at the current descriptor
  279.         {
  280.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;        // if it's an interface descriptor
  281.             if (pMyIntDesc->interfaceNumber == ReqInterface)            // see if it's the request descriptor
  282.             {
  283.                 *hInterfaceDesc = pMyIntDesc;                                    // if it is, then return with hInterfaceDesc set to the
  284.                 return kUSBNoErr;                                                    // current descriptor pointer
  285.             }
  286.         }
  287.         anAddress =        (unsigned long) pCurrentDesc;                        // Nope, that either wasn't an interface descriptor
  288.         anOffset  =        (unsigned long) pCurrentDesc->length;
  289.         anAddress +=    anOffset;
  290.         pCurrentDesc =    (USBDescriptorHeaderPtr) anAddress;
  291.     }                                                                                    // or it was, but not the droid we're looking for.
  292.     return -1;
  293. }
  294.  
  295. //****************************************************************************************************
  296. //
  297. //        StorageClassDriverAPI.c calls end up here...
  298. //
  299. //****************************************************************************************************
  300.  
  301. OSStatus
  302. StorageClassDriverInitialize(void)
  303. {
  304.     return noErr;
  305. }
  306.  
  307.  
  308. OSStatus
  309. StorageClassDriverControl(    UInt32    theControlSelector,
  310.                                     void        *theControlData)
  311. {
  312. #pragma unused (theControlData)
  313.  
  314. OSStatus        status;
  315.  
  316.     switch (theControlSelector)
  317.     {
  318.         case kControlDisableRemoval:
  319.             gOKToRemoval = false;
  320.             status = noErr;
  321.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlDisableRemoval", 0) );
  322.             break;
  323.             
  324.         case kControlEnableRemoval:
  325.             gOKToRemoval = true;
  326.             status = noErr;
  327.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlEnableRemoval", 0) );
  328.             break;
  329.         
  330.         default:
  331.             status = controlErr;
  332.             break;
  333.     }    
  334.     return status;
  335. }
  336.  
  337.  
  338. OSStatus
  339. StorageClassDriverStatus(    UInt32    theInfoSelector,
  340.                                     void        *theInfo)
  341. {
  342. OSStatus        status;
  343.  
  344.     switch (theInfoSelector)
  345.     {
  346.         case kStatusConfiguration:                        // Return the current confifuration status
  347.             *((UInt32*) theInfo) = gConfigureStatus;
  348.             status = noErr;
  349.             break;
  350.             
  351.         case kStatusDeviceStatus:
  352.             status = StorageClassDriverGetStatus( (StorageStatusPBPtr) theInfo );
  353.             break;
  354.         
  355.         case kStatusRemovalStatus:
  356.             *((Boolean*) theInfo) = gOKToRemoval;
  357.             status = noErr;
  358.             break;
  359.             
  360.         default:
  361.             status = statusErr;
  362.             break;
  363.     }    
  364.     return status;
  365. }
  366.  
  367.  
  368. // All device requests come through here
  369. OSStatus
  370. StorageClassDriverExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  371. {
  372. OSStatus            myErr;
  373. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverExecuteCommand", 0) );
  374.  
  375.     // Make sure we have been able to configure the device
  376.     if (gConfigured == false)
  377.     {
  378.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  379.         return kClassNotConfiguredErr;
  380.     }
  381.         
  382.     // check if we already have a read in progress, if so return error.
  383.     if (gCommandPB.busy == true)
  384.     {
  385.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand busy", 0) );
  386.         return kCommandBusyError;
  387.     }
  388.     
  389.     cmdPBPtr->status = kRequestPending;
  390.  
  391.     BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  392.         
  393.     gCommandPB.busy = true;
  394.  
  395.     InitParamBlock(gStorageClassInfo.interfaceRef, &gCommandPB.usbPB);
  396.     
  397.     // Get a local copy of the callers cdb
  398.     BlockCopy(&cmdPBPtr->cdb[0], &gCommandPB.cdb[0], kCDBSize);
  399.     
  400.     gCommandPB.flags = cmdPBPtr->flags;
  401.     
  402.     gCommandPB.userPBPtr = (StorageExecuteCommandPBPtr) cmdPBPtr;                // Save the ptr to the callers PB
  403.     
  404.     gCommandPB.usbPB.usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  405.     
  406.     gCommandPB.usbPB.usb.cntl.BRequest =        0;
  407.     gCommandPB.usbPB.usb.cntl.WValue =            0;
  408.     gCommandPB.usbPB.usb.cntl.WIndex =            0;
  409.     
  410.     gCommandPB.usbPB.usbBuffer =            (Ptr)&gCommandPB.cdb[0];
  411.     gCommandPB.usbPB.usbReqCount =        kCDBSize;
  412.     gCommandPB.usbPB.usbFlags =            0;
  413.         
  414.     gCommandPB.usbPB.usbRefcon =            kStorageExecuteCommand;
  415.     
  416.     gCommandPB.usbPB.usbCompletion =        (USBCompletion)ExecuteCommandCompletion;                // Don't use double buffering for builk I/O
  417.         
  418.     myErr = USBDeviceRequest(&gCommandPB.usbPB);
  419.             
  420.     return myErr;
  421. }
  422.  
  423. static void ExecuteCommandCompletion(USBPB* usbPB)
  424. {
  425. OSStatus                            myErr;
  426. StorageExecuteCommandPBPtr    cmdPBPtr;
  427.  
  428.     // Retrieve the callers pb
  429.     cmdPBPtr = (StorageExecuteCommandPBPtr) gCommandPB.userPBPtr;
  430.         
  431. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 5 ) );
  432.  
  433.     switch(usbPB->usbRefcon)
  434.     {
  435.         case kStorageExecuteCommand:        // Device request completion
  436.             // First check to see if an error occurred on the command out
  437.             if (usbPB->usbStatus != noErr)
  438.             {
  439.                 // Clear stalled control pipe
  440.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageExecuteCommand error. usbStatus:" , usbPB->usbStatus ) );
  441.                 USBClearPipeStallByReference(usbPB->usbReference);
  442.                 cmdPBPtr->status = usbPB->usbStatus;
  443.                                 
  444.                 gCommandPB.busy = false;
  445.                 if(cmdPBPtr->completionProc != nil)
  446.                 {
  447.                     (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  448.                 }
  449.                 break;
  450.             }
  451.             
  452.             // If there is to be no data transfer then we are done and can return to the caller
  453.             if (gCommandPB.flags & kStorageNoData)
  454.             {
  455.                 cmdPBPtr->status = usbPB->usbStatus;
  456.                                 
  457.                 gCommandPB.busy = false;
  458.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  459.                 
  460.                 break;
  461.             }
  462.             // Setup the usb pb for either bulk in or out
  463.             if (gCommandPB.flags & kStorageDataIn)
  464.                 InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  465.             else if (gCommandPB.flags & kStorageDataOut)
  466.                 InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  467.                             
  468.             // Check to see if the amount of data to be transferred is greater
  469.             // than kUSBMaxBulkTransfer.  This is to get around an issue with
  470.             // the USB Manager/USL where the amount of data transferred per
  471.             // Bulk Request needs to be limited to a specific amount
  472.             if ( cmdPBPtr->expectedCount > kUSBMaxBulkTransfer )
  473.             {
  474.                 usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  475.             }
  476.             else
  477.             {
  478.                 usbPB->usbReqCount     = cmdPBPtr->expectedCount;
  479.             }
  480.             
  481.             usbPB->usbRefcon =        kStorageBulkIOComplete;
  482.             usbPB->usbActCount =        0;
  483.             usbPB->usbBuffer =        cmdPBPtr->userBuffer;
  484.             usbPB->usbCompletion =    (USBCompletion)ExecuteCommandCompletion;
  485.             
  486.             // Start a bulk in or out transaction
  487.             if (gCommandPB.flags & kStorageDataIn)
  488.                 myErr = USBBulkRead(&gCommandPB.usbPB);
  489.             else if (gCommandPB.flags & kStorageDataOut)
  490.                 myErr = USBBulkWrite(&gCommandPB.usbPB);
  491.             
  492.             if    (ImmediateError(myErr))
  493.             {
  494.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr) );
  495.                 cmdPBPtr->actualCount =    usbPB->usbActCount;
  496.                 cmdPBPtr->status = myErr;
  497.                 gCommandPB.busy = false;
  498.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  499.             }
  500.             break;
  501.         
  502.         case kStorageBulkIOComplete:
  503.         
  504.             cmdPBPtr->actualCount =    usbPB->usbActCount;                // Update the users byte count
  505.             cmdPBPtr->status =        usbPB->usbStatus;                    // and status
  506.             
  507.             if (usbPB->usbStatus != noErr)                                // Clear a possible pipe stall
  508.             {
  509.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageBulkIOComplete error. usbStatus:" , usbPB->usbStatus ) );
  510.                 USBClearPipeStallByReference(usbPB->usbReference);
  511.             }
  512.             else if ( cmdPBPtr->actualCount != cmdPBPtr->expectedCount)
  513.             {
  514.                 // If we have not yet transfered all the data and there are no Errors
  515.                 // Setup the usb pb for either bulk in or out
  516.                 if (gCommandPB.flags & kStorageDataIn)
  517.                 {
  518.                     InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  519.                 }
  520.                 else if (gCommandPB.flags & kStorageDataOut)
  521.                 {
  522.                     InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  523.                 }
  524.     
  525.                 if ( (cmdPBPtr->expectedCount - cmdPBPtr->actualCount) > kUSBMaxBulkTransfer )
  526.                 {
  527.                     usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  528.                 }
  529.                 else
  530.                 {
  531.                     usbPB->usbReqCount     = (cmdPBPtr->expectedCount - cmdPBPtr->actualCount);
  532.                 }
  533.                 
  534.                 usbPB->usbRefcon         = kStorageBulkIOComplete;
  535.                 usbPB->usbActCount     = 0;
  536.                 usbPB->usbBuffer         = (cmdPBPtr->userBuffer) + (cmdPBPtr->actualCount);
  537.                 usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
  538.                 
  539.                 // Continue a bulk in or out transaction
  540.                 if (gCommandPB.flags & kStorageDataIn)
  541.                 {
  542.                     myErr = USBBulkRead(&gCommandPB.usbPB);
  543.                 }
  544.                 else if (gCommandPB.flags & kStorageDataOut)
  545.                 {
  546.                     myErr = USBBulkWrite(&gCommandPB.usbPB);
  547.                 }
  548.                 
  549.                 if    (ImmediateError(myErr))
  550.                 {
  551.                     USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr);
  552.                     cmdPBPtr->status = myErr;
  553.                     gCommandPB.busy = false;
  554.                     if(cmdPBPtr->completionProc != nil)
  555.                     {
  556.                         (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  557.                     }
  558.                 }
  559.                 break;
  560.             }
  561.             
  562.             gCommandPB.busy = false;
  563.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  564.             break;
  565.             
  566.         default:
  567.             IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: ExecuteCommandCompletion - unknown state!", 5) );
  568.             cmdPBPtr->actualCount =    0;
  569.             cmdPBPtr->status = kUSBInternalErr;
  570.                         
  571.             gCommandPB.busy = false;
  572.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  573.             break;
  574.     }
  575. }
  576.  
  577. OSStatus
  578. StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr )
  579. {
  580. OSStatus    myErr;
  581.     
  582.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverGetStatus", 0) );
  583.  
  584.     // Make sure we have been able to configure the device
  585.     if (gConfigured == false)
  586.     {
  587.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  588.         return kClassNotConfiguredErr;
  589.     }
  590.         
  591.     // check if we already have a status request in progress, if so return error.
  592.     if (gGetStatusPB.busy == true)
  593.     {
  594.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverGetStatus busy", 0) );
  595.         return kCommandBusyError;
  596.     }
  597.     
  598.     BlockZero(&gGetStatusPB, sizeof(StorageClassStatusPB));
  599.     
  600.     gGetStatusPB.busy = true;
  601.     
  602.     gGetStatusPB.userPBPtr = statusPBPtr;
  603.     
  604.     InitParamBlock(gStorageClassInfo.interfaceRef, &gGetStatusPB.usbPB);
  605.             
  606.     gGetStatusPB.usbPB.usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);            
  607.     
  608.     gGetStatusPB.usbPB.usb.cntl.BRequest =            kUSBRqGetStatus;
  609.     gGetStatusPB.usbPB.usb.cntl.WIndex =            0;
  610.     gGetStatusPB.usbPB.usb.cntl.WValue =            0;
  611.     
  612.     gGetStatusPB.usbPB.usbBuffer =            (Ptr)&gGetStatusPB.status[0];
  613.     gGetStatusPB.usbPB.usbReqCount =            kStatusSize;
  614.     gGetStatusPB.usbPB.usbFlags =                0;
  615.         
  616.     gGetStatusPB.usbPB.usbRefcon =            kStorageGetStatus;
  617.     gGetStatusPB.usbPB.usbCompletion =        (USBCompletion)GetStatusCompletion;
  618.             
  619.     myErr = USBDeviceRequest(&gGetStatusPB.usbPB);
  620.             
  621.     return myErr;
  622. }
  623.  
  624.  
  625.  
  626. static void GetStatusCompletion(USBPB* usbPB)
  627. {
  628. StorageStatusPBPtr    userPBPtr;
  629.     
  630.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 6 ) );
  631.     
  632.     // Retrieve the callers pb
  633.     userPBPtr = (StorageStatusPBPtr) gGetStatusPB.userPBPtr;
  634.         
  635.     userPBPtr->status =                usbPB->usbStatus;
  636.     userPBPtr->deviceStatus[0] =    gGetStatusPB.status[0];
  637.     userPBPtr->deviceStatus[1] =    gGetStatusPB.status[1];
  638.                     
  639.     gGetStatusPB.busy = false;
  640.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  641. }
  642.  
  643.  
  644. OSStatus
  645. StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr )
  646. {
  647. OSStatus            myErr;
  648.  
  649.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverAbortTransaction", 0) );
  650.  
  651.     // Make sure we have been able to configure the device
  652.     if (gConfigured == false)
  653.     {
  654.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction not configured", 0) );
  655.         return kClassNotConfiguredErr;
  656.     }
  657.         
  658.     // check if we already have a status request in progress, if so return error.
  659.     if (gControlPB.busy == true)
  660.     {
  661.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction busy", 0) );
  662.         return kCommandBusyError;
  663.     }
  664.     
  665.     BlockZero(&gControlPB, sizeof(StorageControlPB));
  666.     
  667.     gControlPB.busy = true;
  668.     
  669.     gControlPB.userPBPtr = controlPBPtr;
  670.     
  671.     InitParamBlock(gStorageClassInfo.interfaceRef, &gControlPB.usbPB);
  672.             
  673.     gControlPB.usbPB.usb.cntl.BMRequestType =    0x02;            // Clear feature        
  674.     
  675.     gControlPB.usbPB.usb.cntl.BRequest =        kUSBRqClearFeature;
  676.     
  677.     if (controlPBPtr->selector == 0)                        // Abort read pipe
  678.         gControlPB.usbPB.usb.cntl.WIndex =        0x82;
  679.     else                                                            // Abort write pipe
  680.         gControlPB.usbPB.usb.cntl.WIndex =        0x01;
  681.         
  682.     gControlPB.usbPB.usb.cntl.WValue =            0;                // 0 = clear endpoint stall
  683.     
  684.     gControlPB.usbPB.usbBuffer =            nil;
  685.     gControlPB.usbPB.usbReqCount =        0;
  686.     gControlPB.usbPB.usbFlags =            0;
  687.         
  688.     gControlPB.usbPB.usbRefcon =            kStorageGetStatus;
  689.     gControlPB.usbPB.usbCompletion =        (USBCompletion)AbortTransactionCompletion;
  690.             
  691.     myErr = USBDeviceRequest(&gControlPB.usbPB);
  692.             
  693.     return myErr;
  694. }
  695.  
  696.  
  697.  
  698. static void AbortTransactionCompletion(USBPB* usbPB)
  699. {
  700. StorageControlPBPtr    userPBPtr;
  701.     
  702.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 7 ) );
  703.     
  704.     // Retrieve the callers pb
  705.     userPBPtr = (StorageControlPBPtr) gControlPB.userPBPtr;
  706.         
  707.     userPBPtr->status =                usbPB->usbStatus;
  708.                     
  709.     gControlPB.busy = false;
  710.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  711. }
  712.  
  713.  
  714. static void ReadInterruptCompletion(USBPB* usbPB)
  715. {
  716.     gStorageClassInfo.transDepth--;
  717.     
  718.     if (usbPB->usbStatus == kUSBEndpointStallErr)
  719.     {
  720.         USBClearPipeStallByReference(gStorageClassInfo.interruptPipeRef);
  721.     }
  722.     InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  723.  
  724.     usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  725.     usbPB->usbReqCount =        0x02;
  726.     usbPB->usbRefcon =        kStorageReadInterrupt;
  727.     usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  728.     
  729.     StorageDeviceInitiateConfiguration(usbPB);
  730. }
  731.  
  732. void
  733. StorageDeviceInitiateConfiguration(USBPB *usbPB)
  734. {
  735. OSStatus myErr;
  736. StorageClassTransactionPB*    pTransPB = (StorageClassTransactionPB*) usbPB;
  737.  
  738.     gStorageClassInfo.transDepth++;
  739.     
  740.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > kMaxTransitions))
  741.     {
  742.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Illegal Transaction Depth", usbPB->usbRefcon) );
  743.         gConfigureStatus = kConfigureFailed;
  744.     }
  745.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 2 ) );
  746.     
  747.     switch(usbPB->usbRefcon & ~kRetryTransaction)
  748.     {    
  749.         case kGetFullConfiguration:
  750.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  751.             
  752.             usbPB->usb.cntl.WIndex =            0;             // First try configuration 0, if it doesn't succeed, then try config 1
  753.             usbPB->usbRefcon |=        kCompletionPending;
  754.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  755.             
  756.             myErr = USBGetFullConfigurationDescriptor(usbPB);
  757.             if(ImmediateError(myErr))
  758.             {
  759.                 gConfigureStatus = kConfigureFailed;
  760.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration (#0) - immediate error", myErr) );
  761.             }
  762.             break;
  763.         
  764.         case kSetConfig:
  765.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  766.             
  767.             usbPB->usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice);
  768.             usbPB->usb.cntl.BRequest =            kUSBRqSetConfig;
  769.             usbPB->usb.cntl.WValue =            gStorageClassInfo.pFullConfigDescriptor->configValue;         // Use configuration ID value from descriptor
  770.             usbPB->usbRefcon |=             kCompletionPending;
  771.             
  772.             usbPB->usbCompletion =        (USBCompletion)StorageDeviceConfigureCompletion;
  773.             
  774.             myErr = USBDeviceRequest(usbPB);
  775.             if(ImmediateError(myErr))
  776.             {
  777.                 gConfigureStatus = kConfigureFailed;
  778.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kSetConfig - immediate error", myErr) );
  779.             }
  780.             break;
  781.         
  782.         case kFindStorageInterface:
  783.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  784.             usbPB->usbActCount =        0;
  785.  
  786.             usbPB->usbClassType =    kDriverClassID;
  787.             usbPB->usbSubclass =        kDriverSubClassID;
  788.             usbPB->usbProtocol =        0;
  789.             usbPB->usb.cntl.WValue =        0;
  790.             usbPB->usbRefcon |=        kCompletionPending;
  791.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  792.             
  793.             myErr = USBFindNextInterface(usbPB);
  794.             if(ImmediateError(myErr))
  795.             {
  796.                 gConfigureStatus = kConfigureFailed;
  797.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kFindStorageInterface - immediate error", myErr) );
  798.             }
  799.             break;
  800.             
  801.         case kNewInterfaceRef:
  802.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  803.             // Note: gStorageClassInfo.usbWIndex will be set to zero by InitParamBlock
  804.             // so set it again to gStorageClassInfo.interfaceIndex before calling USBNewInterfaceRef
  805.             usbPB->usbActCount =        0;
  806.             usbPB->usb.cntl.WIndex =            gStorageClassInfo.interfaceNumber;
  807.             usbPB->usbRefcon |=        kCompletionPending;
  808.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  809.  
  810.             myErr = USBNewInterfaceRef(usbPB);
  811.             if(ImmediateError(myErr))
  812.             {
  813.                 gConfigureStatus = kConfigureFailed;
  814.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kNewInterfaceRef - immediate error", myErr) );
  815.             }
  816.             break;
  817.                 
  818.         case kStorageConfigureInterface:
  819.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  820.  
  821.             usbPB->usbActCount =        0;
  822.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  823.             usbPB->usbRefcon |=        kCompletionPending;
  824.             
  825.             gStorageClassInfo.interfaceNumber =        0;            // Find First calls 'FindNextInterface' with WIndex = 0
  826.                                                                             // Find Next calls 'FindNextInterface' with WIndex = InterfaceNumber
  827.             
  828.             myErr = USBConfigureInterface(usbPB);
  829.             if (ImmediateError(myErr))
  830.             {
  831.                 gConfigureStatus = kConfigureFailed;
  832.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageConfigureInterface - immediate error", myErr) );
  833.             }
  834.             break;
  835.         
  836.         case kStorageFindInterruptPipe:
  837.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  838.  
  839.             usbPB->usbFlags =            kUSBIn;
  840.             usbPB->usbClassType =    kUSBInterrupt;
  841.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  842.             usbPB->usbRefcon |=        kCompletionPending;
  843.  
  844.             myErr = USBFindNextPipe( usbPB );
  845.             if (ImmediateError(myErr))
  846.             {
  847.                 gConfigureStatus = kConfigureFailed;
  848.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindInterruptPipe - immediate error", myErr) );
  849.                 usbPB->usbRefcon = kReturnFromDriver;
  850.             }
  851.             break;
  852.         
  853.         case kStorageFindBulkInPipe:
  854.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  855.  
  856.             usbPB->usbFlags =            kUSBIn;
  857.             usbPB->usbClassType =    kUSBBulk;
  858.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  859.             usbPB->usbRefcon |=        kCompletionPending;
  860.  
  861.             myErr = USBFindNextPipe( usbPB );
  862.             if (ImmediateError(myErr))
  863.             {
  864.                 gConfigureStatus = kConfigureFailed;
  865.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkInPipe - immediate error", myErr) );
  866.                 usbPB->usbRefcon = kReturnFromDriver;
  867.             }
  868.             break;
  869.         
  870.         case kStorageFindBulkOutPipe:
  871.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  872.  
  873.             usbPB->usbFlags =            kUSBOut;
  874.             usbPB->usbClassType =    kUSBBulk;
  875.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  876.             usbPB->usbRefcon |=        kCompletionPending;
  877.  
  878.             myErr = USBFindNextPipe( usbPB );
  879.             if (ImmediateError(myErr))
  880.             {
  881.                 gConfigureStatus = kConfigureFailed;
  882.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkOutPipe - immediate error", myErr) );
  883.                 usbPB->usbRefcon =    kReturnFromDriver;
  884.             }
  885.             break;
  886.         
  887.         case kStorageReadInterrupt:            
  888.             InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  889.  
  890.             usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  891.             usbPB->usbReqCount =        0x02;
  892.             usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  893.             usbPB->usbRefcon |=        kCompletionPending;
  894.         
  895.             myErr = USBIntRead(usbPB);
  896.             if(ImmediateError(myErr))
  897.             {
  898.                 gConfigureStatus = kConfigureFailed;
  899.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageReadInterrupt - immediate error", myErr) );
  900.             }
  901.             break;
  902.             
  903.         case kReturnFromDriver:
  904.             break;
  905.             
  906.         default:
  907.             gConfigureStatus = kConfigureFailed;
  908.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Transaction initiated with bad refcon value", usbPB->usbRefcon) );
  909.             usbPB->usbRefcon = kUndefined + kReturnFromDriver;
  910.             break;
  911.     }
  912.     
  913. // At this point the control is returned to the system.  If a USB transaction
  914. // has been initiated, then it will call the Complete procs
  915. // (below) to handle the results of the transaction.
  916. }
  917.  
  918. static void
  919. StorageDeviceConfigureCompletion(USBPB *usbPB)
  920. {
  921. StorageClassTransactionPB*        pTransPB = (StorageClassTransactionPB*) usbPB;
  922. USBInterfaceDescriptorPtr        pInterfaceDescriptor;
  923. UInt32                                i;
  924.  
  925.     gStorageClassInfo.transDepth--;
  926.         
  927.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 3 ) );
  928.     
  929.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > 1))
  930.     {
  931.         gConfigureStatus = kConfigureFailed;
  932.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Illegal Transaction Depth", gStorageClassInfo.transDepth) );
  933.     }
  934.     
  935.     // We should only retry if the error is a USB transaction problem
  936.     // Device errors are handled outside of the state machine.
  937.     if ((usbPB->usbStatus != noErr) && (usbPB->usbStatus != kUSBPending))
  938.     {
  939.         IF_DEBUG( USBExpertStatus(usbPB->usbReference, "\pStorage Driver: Completion Error", usbPB->usbStatus) );
  940.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  941.         usbPB->usbRefcon |= kRetryTransaction;
  942.         gStorageClassInfo.retryCount--;
  943.         if (!gStorageClassInfo.retryCount)
  944.         {
  945.             gConfigureStatus = kConfigureFailed;
  946.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Too many retries", usbPB->usbRefcon) );
  947.             usbPB->usbRefcon = kReturnFromDriver;
  948.             return;
  949.         }
  950.     }
  951.     else
  952.     {
  953.         usbPB->usbRefcon &= ~kRetryTransaction;
  954.         gStorageClassInfo.retryCount = kStorageRetryCount;
  955.     }
  956.  
  957.     if (usbPB->usbRefcon & kCompletionPending)             
  958.     {                                                
  959.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  960.         switch(usbPB->usbRefcon)
  961.         {
  962.             case kGetFullConfiguration:
  963.                 usbPB->usbRefcon = kSetConfig;
  964.                 gStorageClassInfo.pFullConfigDescriptor = usbPB->usbBuffer;        // Save the config descriptor
  965.                 if (gStorageClassInfo.pFullConfigDescriptor == nil)
  966.                 {
  967.                     gConfigureStatus = kConfigureFailed;
  968.                     usbPB->usbRefcon = kReturnFromDriver;
  969.                     
  970.                     IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration - pointer is nil", usbPB->usbRefcon) );
  971.                 }
  972.                 break;
  973.                 
  974.             case kSetConfig:
  975.                 BlockCopy(    (void *) &gStorageClassInfo.pFullConfigDescriptor,
  976.                                 (void *) &gStorageClassInfo.partialConfigDescriptor,
  977.                                 (Size) (sizeof(USBConfigurationDescriptor) ) );
  978.                 
  979.                 for (i=0; i < gStorageClassInfo.partialConfigDescriptor.numInterfaces; i++)
  980.                 {
  981.                     gStorageClassInfo.interfaceRefArray[i] = 0;
  982.                     
  983.                     GetInterfaceDescriptor(    gStorageClassInfo.pFullConfigDescriptor,
  984.                                                     i,
  985.                                                     &pInterfaceDescriptor);
  986.                     BlockCopy(    (void *)pInterfaceDescriptor,
  987.                                     (void *)(&(gStorageClassInfo.interfaceDescriptors[i])),
  988.                                     (Size)(pInterfaceDescriptor->length));
  989.                 }
  990.                 
  991.                 gStorageClassInfo.pInterfaceDescriptor = &(gStorageClassInfo.interfaceDescriptors[0]);
  992.                 
  993.                 gStorageClassInfo.interfaceIndex =        0;
  994.                 gStorageClassInfo.interfaceCount =        gStorageClassInfo.partialConfigDescriptor.numInterfaces;
  995.                 usbPB->usbRefcon =                            kFindStorageInterface;
  996.                 break;
  997.                 
  998.             case kFindStorageInterface:
  999.                 gStorageClassInfo.interfaceNumber =        usbPB->usb.cntl.WIndex;
  1000.                 usbPB->usbRefcon =                            kNewInterfaceRef;
  1001.                 break;
  1002.                 
  1003.             case kNewInterfaceRef:
  1004.                 gStorageClassInfo.interfaceRef =        usbPB->usbReference;
  1005.                 usbPB->usbRefcon =                        kStorageConfigureInterface;
  1006.                 break;
  1007.                 
  1008.             case kStorageConfigureInterface:
  1009.                 usbPB->usbRefcon = kStorageFindInterruptPipe;
  1010.                 break;
  1011.             
  1012.             case kStorageFindInterruptPipe:                                
  1013.                 gStorageClassInfo.interruptPipeRef =     usbPB->usbReference;
  1014.                 usbPB->usbRefcon =                            kStorageFindBulkInPipe;
  1015.                 break;
  1016.                 
  1017.             case kStorageFindBulkInPipe:
  1018.                 gStorageClassInfo.readPipeRef =     usbPB->usbReference;
  1019.                 usbPB->usbRefcon =                    kStorageFindBulkOutPipe;
  1020.                 break;
  1021.             
  1022.             case kStorageFindBulkOutPipe:
  1023.                 gStorageClassInfo.writePipeRef = usbPB->usbReference;
  1024.                 gConfigured = true;                                // Set the configured flag so we can respond to calls via the dispatch table
  1025.                 gConfigureStatus = kConfigureComplete;        // Flag for client to determine that we are no configured
  1026.                 IF_DEBUG(USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: Driver Configured.", 3 ) );            
  1027.                 usbPB->usbRefcon = kReturnFromDriver;
  1028.                 break;
  1029.             
  1030.             case kStorageReadInterrupt:    
  1031.     //            ProcessStorageInterrupt(pStoragePB);
  1032.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 0:", gStorageClassInfo.interruptReport[0] ));
  1033.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 1:", gStorageClassInfo.interruptReport[1] ));
  1034.                 
  1035.                 usbPB->usbRefcon = kStorageReadInterrupt;
  1036.                 break;
  1037.     
  1038.             case kNilCompletion:
  1039.             default:
  1040.                 if ( usbPB->usbStatus == noErr )
  1041.                     usbPB->usbRefcon = kUndefined | kReturnFromDriver;
  1042.                 break;
  1043.         }
  1044.     }
  1045.     
  1046.     if ( usbPB->usbStatus == noErr )
  1047.     {
  1048.         if (!(usbPB->usbRefcon & kReturnFromDriver))
  1049.             StorageDeviceInitiateConfiguration(usbPB);
  1050.     }
  1051.     else
  1052.     {
  1053.         gConfigureStatus = kConfigureFailed;
  1054.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, StateStr(usbPB->usbRefcon, kPString), usbPB->usbRefcon) );
  1055.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, USBStatusStr(usbPB->usbStatus, kPString), 0) );
  1056.     }
  1057. }
  1058.  
  1059.  
  1060. void 
  1061. StorageDriverEntry(    USBDeviceRef                    deviceRef,
  1062.                             USBDeviceDescriptorPtr        deviceDescriptorPtr,
  1063.                             USBInterfaceDescriptorPtr    pInterfaceDescriptor)
  1064. {
  1065.     UInt32    usbVersion;
  1066.             
  1067.     IF_DEBUG( USBExpertStatus(deviceRef, "\pStorage Driver Entry" , 1 ) );
  1068.     
  1069.     if( !gBeenThereDoneThat)
  1070.     {
  1071.         gBeenThereDoneThat = true;
  1072.         
  1073.         // Check for the correct version of the USB manager.
  1074.         // We are ok with all version later than 1.0
  1075.         
  1076.         if (GetUSBVersion(&usbVersion) == noErr)
  1077.         {
  1078.             if ((usbVersion & 0xffff0000) < 0x01010000)        // Wrong USB version number so do NOT continue
  1079.             {
  1080.                 IF_DEBUG( USBExpertStatus(deviceRef, "\pWrong version of the USB Manager" , 1 ) );
  1081.                                 
  1082.                 IF_DEBUG( USBExpertFatalError(deviceRef, 0, "\pWrong USB Manager version" , 0) );
  1083.                 gConfigured = false;                                // Set the configured flag so we can respond to calls via the dispatch table
  1084.                 gConfigureStatus = kConfigureFailed;        // Flag for client to determine that configuration failed
  1085.                 
  1086.                 return ;
  1087.             }
  1088.         }
  1089.         
  1090.         // Initialize the global data structures
  1091.         BlockZero(&gStorageClassInfo, sizeof(StorageClassInfo));
  1092.         BlockZero(&gInterruptPB, sizeof(StorageClassTransactionPB));
  1093.         BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  1094.         
  1095.         gStorageClassInfo.retryCount =                kStorageRetryCount;
  1096.         gStorageClassInfo.deviceDescriptor =        *deviceDescriptorPtr;        // keep a copy of the device descriptor
  1097.         gStorageClassInfo.pInterfaceDescriptor =    pInterfaceDescriptor;
  1098.         gStorageClassInfo.deviceRef =                    deviceRef;
  1099.         gStorageClassInfo.interfaceRef =                deviceRef;
  1100.         gStorageClassInfo.transDepth =                0;                                    // init Delay Callback Depth
  1101.  
  1102.         InitParamBlock( deviceRef, &gStorageClassInfo.usbPB );
  1103.                 
  1104.         //    Start out at first state
  1105.         if (gStorageClassInfo.pInterfaceDescriptor != NULL)
  1106.         {
  1107.             gStorageClassInfo.usbPB.usbRefcon = kStorageConfigureInterface;
  1108.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as interface driver" , 0 ) );
  1109.         }
  1110.         else
  1111.         {
  1112.             gStorageClassInfo.usbPB.usbRefcon = kGetFullConfiguration;
  1113.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as device driver" , 0 ) );
  1114.         }
  1115.         
  1116.         gConfigureStatus = kConfigureInProgress;
  1117.         StorageDeviceInitiateConfiguration(&gStorageClassInfo.usbPB);
  1118.     }
  1119. }
  1120.  
  1121.  
  1122. void
  1123. StorageClassDriverFinalize( void )
  1124. {
  1125. OSStatus    status;
  1126.  
  1127.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverFinalize." , 0 ) );
  1128.     
  1129.     //
  1130.     // Make sure all pipes are finished with transactions by calling the USBAbortPipeByReference function
  1131.     //
  1132.     status = USBAbortPipeByReference(gStorageClassInfo.deviceRef);                // Control pipe
  1133.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Control pipe" , status ) );
  1134.     
  1135.     status = USBAbortPipeByReference(gStorageClassInfo.interruptPipeRef);    // Interrupt pipe
  1136.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Interrupt pipe" , status ) );
  1137.     
  1138.     status = USBAbortPipeByReference(gStorageClassInfo.readPipeRef);            // Read pipe
  1139.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Read pipe" , status ) );
  1140.     
  1141.     status = USBAbortPipeByReference(gStorageClassInfo.writePipeRef);            // Write pipe
  1142.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Write pipe" , status ) );
  1143. }
  1144.  
  1145.  
  1146. OSStatus    
  1147. StorageClassDriverNotifyProc(UInt32    notification, void* pointer)
  1148. {
  1149. #pragma unused (notification, pointer)
  1150. OSStatus status = noErr;
  1151.         
  1152.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gConfigureStatus: " , gConfigureStatus ) );
  1153.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gOKToRemoval: " , gOKToRemoval ) );
  1154.     
  1155.     // Don't allow removal if we are busy configuration the interface.
  1156.     if (gConfigureStatus == kConfigureInProgress)
  1157.     {
  1158.         status = kUSBDeviceBusy;
  1159.     }
  1160.     
  1161.     // Don't allow removal until the Shim says it's ok
  1162.     if (gOKToRemoval == false)
  1163.     {
  1164.         status = kUSBDeviceBusy;
  1165.     }
  1166.     
  1167.     return (status);
  1168. }
  1169.